from src.game.entity.entity import Entity
from src.event.entity import EntityLivingDeathEvent, EntityLivingDamageEvent
from src.handler.event import EventHandler
from src.game.ai.state import StateMachine
from src.helper.movement import MovementHelper
from src.game.buff import Buff
from src.game.talent import Talent
from src.storage.pso import PSO
from pymunk.vec2d import Vec2d

class EntityLiving(Entity):

    name = "entityliving"

    def __init__(self, maxHealth, talent):
        Entity.__init__(self)
        self.ai = StateMachine()
        self.hasAI = False
        self.maxHealth = maxHealth
        self.health = maxHealth
        self.isDead = False
        self.view = 0.
        self.talent = talent
        self.buffs = []
        
    def addBuff(self, buff):
        buff.entity = self
        buff.addEffect()
        self.buffs.append(buff)
        
    def removeBuff(self, buff):
        buff.removeEffect()
        self.buffs.remove(buff)
        
    def getViewingVector(self):
        return MovementHelper.deg2vec(self.view)
    
    def distanceTo(self, vec):
        return Vec2d(self.x, self.y).get_distance(vec)

    def onDamage(self, source, name, damage):
        return self.talent.handleDamage(source, name, damage, self.health)

    def update(self):
        if self.hasAI:
            self.ai.update()
        for buff in self.buffs:
            if buff.age < buff.lifetime:
                buff.age += 1
                buff.doEffect()
            else:
                self.removeBuff(buff)
        
        Entity.update(self)
        
        if self.isDead:
            EventHandler.post(EntityLivingDeathEvent(self))
            self.world.entities.remove(self)
            del self

    """
    Handles incoming damage
    source: 0 = Block, 1 = Entity, 2 = Buff
    name: Block/Entity/Buff name
    damage: amount of damage in health
    """
    def damage(self, source, name, damage):
        self.health = self.onDamage(source, name, damage)
        EventHandler.post(EntityLivingDamageEvent(self, source, name, damage))
        if self.health <= 0:
            self.health = 0
            self.isDead = True
            
    def heal(self, health):
        self.health += health
        if self.health > self.maxHealth:
            self.health = self.maxHealth

    def readFromPSO(self, pso):
        Entity.readFromPSO(self, pso)
        self.health = pso.get("health")
        self.isDead = pso.get("dead")
        self.talent = Talent.loadFromPSO(pso)
        self.talent.entity = self
        buffDatas = pso.get("buffs")
        if buffDatas is not None:
            for buffData in buffDatas:
                buffElement = PSO(buffData)
                buff = Buff.loadFromPSO(buffElement)
                buff.entity = self
                self.buffs.append(buff)
        

    def writeToPSO(self, pso):
        Entity.writeToPSO(self, pso)
        pso.set("health", self.health)
        pso.set("dead", self.isDead)
        if self.talent is not None:
            self.talent.writeToPSO(pso)
        buffData = []
        for buff in self.buffs:
            buffElement = PSO()
            buff.writeToPSO(buffElement)
            buffData.append(buffElement.getPickle())
        pso.set("buffs", buffData)